﻿#include <stdio.h>
#include<stdlib.h>
#include <GL/glut.h>
#include <GL/freeglut_ext.h>

GLuint texture_id1;  //纹理id
GLUquadricObj* q = gluNewQuadric(); //创建二次曲面对象

bool mouseLeftDown; //鼠标左键按下
bool mouseRightDown;
float mouseX, mouseY; //上一刻鼠标位置的坐标，以视框左上角为原点
float cameraDistance; // 视角距离
float cameraAngleX; //视角坐标
float cameraAngleY;
float sizeX = 1.0, sizeY = 1.0, sizeZ = 1.0; //放大缩小的比例系数

int load_texture(char* file_name, int width, int height, int depth,GLenum colour_type, GLenum filter_type); //加载纹理
void LoadTextures(GLuint texture_id, int MaxNrOfTextures); //加载纹理
void init(void);
void display(void);
void reshape(int w, int h);
void mouseCB(int button, int state, int x, int y); // 鼠标按键监听
void mouseMotionCB(int x, int y);  // 鼠标按键逻辑
void mouseWheelCB(int button, int dir, int x, int y); // 鼠标滚轮监听和逻辑处理


int load_texture(char* file_name, int width, int height, int depth, 
    GLenum colour_type, GLenum filter_type) //加载纹理
{
    GLubyte* raw_bitmap; //声明位图对象
    FILE* file;
    int errnum;
    if ((errnum = fopen_s(&file, file_name, "rb")) != 0) //文件读取成功才返回0
    {
        return 1;
    }

    raw_bitmap = (GLubyte*)malloc(width * height * depth * (sizeof(GLubyte))); //创建位图

    if (raw_bitmap == NULL)
    {
        fclose(file);
        return 2;
    }

    fread(raw_bitmap, width * height * depth, 1, file); //将文件中图片信息以二进制读入位图中
    fclose(file);

    //  设置过滤类型
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_type);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_type);

    //  设置纹理环境
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, colour_type,
        GL_UNSIGNED_BYTE, raw_bitmap);
    free(raw_bitmap);
    return 0;
}

void LoadTextures(GLuint texture_id, int MaxNrOfTextures) //读入图片创建纹理
{
    char name[] = "D:\\code\\OpenGL\\earth.bmp";
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glGenTextures(MaxNrOfTextures, &texture_id);
    glBindTexture(GL_TEXTURE_2D, 1); 
    if (load_texture(name, 720, 450, 24, GL_BGR_EXT, GL_NEAREST))
    {
        exit(1);
    }
}

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    LoadTextures(texture_id1, 1); 
    glEnable(GL_TEXTURE_2D); //启用二维纹理
    glClearDepth(1.0f);    // 设置深度缓存
    glDepthFunc(GL_LEQUAL);  // 选择深度测试方式
    glEnable(GL_DEPTH_TEST);  // 开启深度测试
    glShadeModel(GL_SMOOTH);  // 阴暗处理采用平滑方式
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 最精细的透视计算
    glBindTexture(GL_TEXTURE_2D, 1); //绑定二维纹理
    gluQuadricDrawStyle(q, GLU_FILL); //设置二次曲面绘制风格，采用多边形模拟
    gluQuadricNormals(q, GLU_SMOOTH); //设置法线风格，采用对每个顶点都设置法向量
    gluQuadricTexture(q, GL_TRUE); //设置自动计算纹理
    return;
}

void display(void)
{
    glPushMatrix();
    // 清除颜色和深度缓存
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glScalef(sizeX, sizeY, sizeZ); //放缩
    glTranslatef(0, 0, cameraDistance); // 移动
    glRotatef(cameraAngleX, 1, 0, 0); // 旋转
    glRotatef(cameraAngleY, 0, 1, 0); // 旋转
    gluSphere(q, 3.0, 50, 40); //二次曲面画地球
    glPopMatrix();
    glutSwapBuffers();
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h); //设置视口
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 0.1, 20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(15.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0);
}


// 鼠标按键监听
void mouseCB(int button, int state, int x, int y)
{
    mouseX = x;
    mouseY = y;

    if (button == GLUT_LEFT_BUTTON)
    {
        if (state == GLUT_DOWN)
        {
            mouseLeftDown = true;
        }
        else if (state == GLUT_UP)
            mouseLeftDown = false;
    }

    else if (button == GLUT_RIGHT_BUTTON)
    {
        if (state == GLUT_DOWN)
        {
            mouseRightDown = true;
        }
        else if (state == GLUT_UP)
            mouseRightDown = false;
    }
}


// 鼠标按键逻辑
void mouseMotionCB(int x, int y)
{
    if (mouseLeftDown) 
    {
        cameraAngleY += (x - mouseX);
        cameraAngleX += (y - mouseY);
        mouseX = x;
        mouseY = y;
    }
    if (mouseRightDown)
    {
        cameraDistance += (y - mouseY) * 0.2f;
        mouseY = y;
    }
    glutPostRedisplay();
}

// 鼠标滚轮监听和逻辑处理
void mouseWheelCB(int button, int dir, int x, int y)
{
    if (dir > 0)
    {
        sizeX++;
        sizeY++;
        sizeZ++;
    }
    else
    {
        sizeX--;
        sizeY--;
        sizeZ--;
    }
    glutPostRedisplay();
}

//void keyboardCB(unsigned char key,int x,int y) {
//    switch (key) {
//    case '1':
//        sizeX++;
//        sizeY++;
//        sizeZ++;
//        break;
//
//    case '2':
//        sizeX--;
//        sizeY--;
//        sizeZ--;
//        break;
//    }
//}


int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(1000, 600);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutMouseFunc(mouseCB);
    glutMotionFunc(mouseMotionCB);
    glutMouseWheelFunc(mouseWheelCB);
    //glutKeyboardFunc(keyboardCB);
    glutDisplayFunc(&display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 0;
}